package generics;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;

import engine.Attribute;

import gui.Canvas;

/**
 * This abstract class implements a group of objects to be
 * animated in the canvas.
 * 
 * @author jianweigan, Thomas Marmaduke
 *
 */
public abstract class AbstractGroup {

	private Map<String, Integer> myParameterMap;
	private List<AbstractGroupMember> myMembers;
	private List<Attribute> myAttributes;
	private int myIndex;

	public AbstractGroup(Dimension d, Integer index,
			SortedMap<String, List<Integer>> myParameterData) {
		myMembers = new ArrayList<AbstractGroupMember>();
		myIndex = index;
		myAttributes = new ArrayList<Attribute>();
		myParameterMap = new HashMap<String, Integer>();
		Iterator<Map.Entry<String, List<Integer>>> iter = myParameterData
				.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry<String, List<Integer>> pairs = iter.next();
			myAttributes.add(new Attribute(pairs.getKey(), pairs.getValue()));
		}

		updateParameter();
	}

	/**
	 * Need this get method to allow subclasses to access mover list
	 */
	public List<AbstractGroupMember> getMembers() {
		return myMembers;
	}

	/**
	 * Need this get so settings panel can access the attributes to create
	 * sliders for each one.
	 */
	public List<Attribute> getAttributeList() {
		return myAttributes;
	}

	/**
	 * Necessary for the subclass to access parameters 
	 */
	public int getParameterValue(String parameter) {
		return myParameterMap.get(parameter);
	}

	/**
	 * Called by canvas to draw the group on the canvas
	 */
	public void paint(Graphics pen) {
		for (AbstractGroupMember member : myMembers) {
			member.paint(pen);
		}
	}

	/**
	 * Called by the canvas to update groups on the canvas.
	 * Implement this by determining what needs to be updated in this
	 * group for the next frame.
	 */
	public abstract void update(Canvas canvas);

	/**
	 * Updates group's current parameters from its attributes list.
	 * Protected because called by 
	 */
	protected void updateParameter() {
		for (Attribute b : myAttributes) {
			myParameterMap.put(b.getName(), b.getCurrentValue());
		}
	}

	/**
	 * Adds a mover to the group
	 */
	public void addMover(AbstractGroupMember newmember) {
		myMembers.add(newmember);
	}

	/**
	 * Removes the newest mover in the group
	 */
	public void removeNewestMover() {
		myMembers.remove(myMembers.size() - 1);
	}

	/**
	 * should return "(GroupName) (Number)"
	 * Cannot implement here because you need to getClass() which would
	 * always return Group instead of e.g. Flock
	 */
	public abstract String toString();

	public int getIndex() {
		return myIndex;
	}

	/**
	 * @return Point with the center of the group's coordinates
	 */
	public Point getGroupCenter() {
		Point center = new Point(0, 0);
		for (AbstractGroupMember member : myMembers) {
			center.x += member.getCenter().x;
			center.y += member.getCenter().y;
		}
		center.x = (int) (center.x / myMembers.size());
		center.y = (int) (center.y / myMembers.size());
		return center;
	}

	/**
	 * @return Point with average velocity of group's members
	 */
	public Point getAverageVelocity() {
		Point avgvelocity = new Point(0, 0);
		for (AbstractGroupMember member : myMembers) {
			avgvelocity.x += member.getVelocity().x;
			avgvelocity.y += member.getVelocity().y;
		}
		avgvelocity.x = (int) (avgvelocity.x / myMembers.size());
		avgvelocity.y = (int) (avgvelocity.y / myMembers.size());
		return avgvelocity;
	}
}
